﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
using MyCompany.WebCrawler.Interfaces;

namespace MyCompany.WebCrawler.Domain
{
    public class Downloader : IDownloader
    {
        public string Page { get; set; }
        public List<string> Links { get; set; }
        public string BaseUrl { get; set; }

        public Downloader()
        {
            Links = new List<string>();
        }

        public List<string> GetLinksFrom(string url)
        {
            BaseUrl = url;

            LoadPage(url);
            ExtractLinks();
            UpdateLinks();
            RemoveBadLinks();

            return Links;
        }

        public string LoadPage(string url)
        {
            Trace.WriteLine("DownloadPage: " + url);
            BaseUrl = url;

            try
            {
                Page = DownloadString(BaseUrl);
            }
            catch (Exception e)
            {
                Trace.WriteLine("EXCEPTION: " + e);
                throw;
            }

            return Page;
        }

        public virtual string DownloadString(string url)
        {
            Trace.WriteLine("DownloadString: " + url);
            using (var client = new System.Net.WebClient())
            {
                return client.DownloadString(url);
            }
        }

        public List<string> ExtractLinks()
        {
            Trace.WriteLine("ExtractLinks");

            Links = new List<string>();
            if (Page == null)
            {
                Trace.WriteLine("Hmm... there is no page. Please LoadPage first.");
                return Links;
            }

            var ahrefMatches = Regex.Matches(Page, @"(<a.*?>.*?</a>)", RegexOptions.Singleline);

            foreach (Match match in ahrefMatches)
            {
                string value = match.Groups[1].Value;

                var urlMatch = Regex.Match(value, @"href=\""(.*?)\""", RegexOptions.Singleline);

                if (urlMatch.Success)
                {
                    var url = urlMatch.Groups[1].Value;
                    Links.Add(url);
                }
            }

            Trace.WriteLine("Total links: " + Links.Count);
            return Links;
        }
        
        private void UpdateLinks()
        {
            Trace.WriteLine("Update links: " + Links.Count);

            var result = new List<string>();
            foreach (var link in Links.ToArray())
            {
                result.Add(UpdateLink(link));
            }
            Links = result;
        }

        public string UpdateLink(string link)
        {
            if (link.ToLower().StartsWith("http"))
                return link;

            var baseUri = new Uri(BaseUrl);
            var myUri = new Uri(baseUri, link);
            var result = myUri.ToString();

            Trace.WriteLine(String.Format("Convert {0} to {1}", link, result));
            return result;
        }

        public void RemoveBadLinks()
        {
            foreach (var link in Links.ToArray())
            {
                if (!link.ToLower().StartsWith("http"))
                {
                    Trace.WriteLine("Remove a bad link: " + link);
                    Links.Remove(link);
                }
            }
        }
    }
}